﻿//-----------------------------------------------------------------------
// <copyright file="FlowController.cs" company="Sławomir Rosiek">
//     Copyright (c) Sławomir Rosiek. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------

namespace Rosieks.Web.Flow
{
    using System;
    using System.Reflection;
    using System.Web.Mvc;
    using Rosieks.Web.Flow.Internals;
    using Rosieks.Web.Flow.Metadata;

    [WebflowAccessable]
    public class FlowController : Controller
    {
        private static readonly MethodInfo tryUpdateModel2;
        private static readonly MethodInfo tryUpdateModel5;

        static FlowController()
        {
            FlowController.tryUpdateModel2 = ReflectionHelper.GetGenericMethod<FlowController, bool>(c => c.TryUpdateModel<string>(null, null as IValueProvider));
            FlowController.tryUpdateModel5 = ReflectionHelper.GetGenericMethod<FlowController, bool>(c => c.TryUpdateModel<string>(null, new string[0], null as IValueProvider));
        }

        public WebflowContext WebflowContext
        {
            get
            {
                return WebflowContext.GetCurrent(this.HttpContext);
            }
        }

        [HttpGet]
        [WebflowAction(NameByParam = "flowName", Order = 1000)]
        [KeepModelState(Order = 999)]
        public virtual ActionResult OnState(string flowName, string actionName)
        {
            return new WebflowResult(actionName, this.WebflowContext.Model);
        }

        [HttpPost]
        [WebflowAction(NameByParam = "flowName", Order = 1000)]
        [KeepModelState(Order = 999)]
        public virtual ActionResult OnState(string flowName, [ModelBinder(typeof(ActionNameBinder))]string actionName, FormCollection form)
        {
            var model = this.WebflowContext.Model;

            var includeProperties = ((ViewState)this.WebflowContext.CurrentState).IncludeFields;
            if (string.IsNullOrEmpty(includeProperties))
            {
                this.TryUpdateModel(model.GetType(), model, form);
            }
            else
            {
                this.TryUpdateModel(model.GetType(), model, includeProperties.Split(','), form);
            }

            return new WebflowResult(actionName, this.WebflowContext.Model);
        }

        protected override void HandleUnknownAction(string actionName)
        {
            if (!this.ActionInvoker.InvokeAction(this.ControllerContext, "OnState"))
            {
                base.HandleUnknownAction(actionName);
            }
        }

        protected virtual bool TryUpdateModel(Type type, object model, IValueProvider form)
        {
            var method = FlowController.tryUpdateModel2.MakeGenericMethod(type);

            return (bool)method.Invoke(this, new[] { model, form });
        }

        protected virtual bool TryUpdateModel(Type type, object model, string[] includeProperties, IValueProvider form)
        {
            var method = FlowController.tryUpdateModel5.MakeGenericMethod(type);

            return (bool)method.Invoke(this, new[] { model, includeProperties, form });
        }
    }
}
